// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';

import 'package:csv/csv.dart';
import 'package:meta/meta.dart';

void main() {
  var csv = new CsvCodec(eol: "\n");
  var data = csv.decoder.convert(new File("data.csv").readAsStringSync());

  // Remove comments and empty lines.
  data.removeWhere((row) => row.length < 3);

  new Directory("lib/src/generated").createSync(recursive: true);

  _writeGlyphSetInterface(data);
  _writeGlyphSet(data, ascii: false);
  _writeGlyphSet(data, ascii: true);
  _writeTopLevel(data);

  var result = Process.runSync(
      "pub", ["run", "dart_style:format", "-w", "lib/src/generated"]);
  print(result.stderr);
  exit(result.exitCode);
}

/// Writes `lib/src/generated/glyph_set.dart`.
void _writeGlyphSetInterface(List<List> data) {
  var file = new File("lib/src/generated/glyph_set.dart")
      .openSync(mode: FileMode.write);
  file.writeStringSync(r"""
    // Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
    // for details. All rights reserved. Use of this source code is governed by a
    // BSD-style license that can be found in the LICENSE file.

    // Don't modify this file by hand! It's generated by tool/generate.dart.

    /// A class that provides access to every configurable glyph.
    ///
    /// This is provided as a class so that individual chunks of code can choose
    /// between [ascii] and [unicode] glyphs. For example:
    ///
    /// ```dart
    /// import 'package:term_glyph/term_glyph.dart' as glyph;
    ///
    /// /// Adds a vertical line to the left of [text].
    /// ///
    /// /// If [unicode] is `true`, this uses Unicode for the line. If it's
    /// /// `false`, this uses plain ASCII characters. If it's `null`, it
    /// /// defaults to [glyph.ascii].
    /// void addVerticalLine(String text, {bool unicode}) {
    ///   var glyphs =
    ///       (unicode ?? !glyph.ascii) ? glyph.unicodeGlyphs : glyph.asciiGlyphs;
    ///
    ///   return text
    ///       .split("\n")
    ///       .map((line) => "${glyphs.verticalLine} $line")
    ///       .join("\n");
    /// }
    /// ```
    abstract class GlyphSet {
      /// Returns [glyph] if [this] supports Unicode glyphs and [alternative]
      /// otherwise.
      String glyphOrAscii(String glyph, String alternative);
  """);

  for (var glyph in data) {
    for (var line in glyph[3].split("\n")) {
      file.writeStringSync("/// $line\n");
    }

    file.writeStringSync("String get ${glyph[0]};");
  }

  file.writeStringSync("}");
  file.closeSync();
}

/// Writes `lib/src/generated/${prefix.toLowerCase()}_glyph_set.dart`.
///
/// If [ascii] is `true`, this writes the ASCII glyph set. Otherwise it writes
/// the Unicode glyph set.
void _writeGlyphSet(List<List> data, {@required bool ascii}) {
  var file = new File(
          "lib/src/generated/${ascii ? "ascii" : "unicode"}_glyph_set.dart")
      .openSync(mode: FileMode.write);

  var className = "${ascii ? "Ascii" : "Unicode"}GlyphSet";
  file.writeStringSync("""
    // Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
    // for details. All rights reserved. Use of this source code is governed by a
    // BSD-style license that can be found in the LICENSE file.

    // Don't modify this file by hand! It's generated by tool/generate.dart.

    import 'glyph_set.dart';

    /// A [GlyphSet] that includes only ${ascii ? "ASCII" : "Unicode"} glyphs.
    class $className implements GlyphSet {
      const $className();
      /// Returns [glyph] if [this] supports Unicode glyphs and [alternative]
      /// otherwise.
      String glyphOrAscii(String glyph, String alternative) =>
          ${ascii ? "alternative" : "glyph"};
  """);

  var index = ascii ? 2 : 1;
  for (var glyph in data) {
    for (var line in glyph[3].split("\n")) {
      file.writeStringSync("/// $line\n");
    }

    file.writeStringSync("""
      ///
      /// Always ${_quote(glyph[index])} for [this].
      String get ${glyph[0]} => ${_quote(glyph[index])};
    """);
  }

  file.writeStringSync("}");
  file.closeSync();
}

/// Writes `lib/src/generated/top_level.dart`.
void _writeTopLevel(List<List> data) {
  var file = new File("lib/src/generated/top_level.dart")
      .openSync(mode: FileMode.write);

  file.writeStringSync("""
    // Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
    // for details. All rights reserved. Use of this source code is governed by a
    // BSD-style license that can be found in the LICENSE file.

    // Don't modify this file by hand! It's generated by tool/generate.dart.

    import '../../term_glyph.dart' as glyph;
  """);

  for (var glyph in data) {
    for (var line in glyph[3].split("\n")) {
      file.writeStringSync("/// $line\n");
    }

    file.writeStringSync("""
      ///
      /// If [ascii] is `false`, this is "${glyph[1]}". If it's `true`, this is
      /// "${glyph[2]}" instead.
      String get ${glyph[0]} => glyph.glyphs.${glyph[0]};
    """);
  }

  file.closeSync();
}

String _quote(String input) => input.contains('"') ? "'$input'" : '"$input"';
